package com.kang.listener;

import com.kang.MsgResult;
import com.kang.bean.bot.*;
import com.kang.service.warMap.*;
import love.forte.common.ioc.annotation.Depend;
import love.forte.simbot.annotation.OnlySession;
import love.forte.simbot.api.message.results.GroupMemberInfo;
import love.forte.simbot.api.sender.Getter;
import love.forte.simbot.api.sender.Sender;
import love.forte.common.ioc.annotation.Beans;
import love.forte.simbot.annotation.Filter;
import love.forte.simbot.annotation.OnGroup;
import love.forte.simbot.api.message.events.GroupMsg;
import love.forte.simbot.bot.BotManager;
import love.forte.simbot.filter.MatchType;
import love.forte.simbot.listener.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;

/**
 * @program: service
 * @description:
 * @author: K.faWu
 * @create: 2022-06-13 15:26
 **/

@Beans
@Component
public class TestListener {

    @Depend
    @Autowired
    private BotManager manager;
    @Autowired
    private WarMapService warMapService;
    @Autowired
    private MapTypeService mapTypeService;
    @Autowired
    private CityService cityService;

    /* 随便给分组取个名字啥的 */

    private static final String PHONE_GROUP = "==tellMeYourNameAndPhone==PHONE==";
    private static final String NAME_GROUP = "==tellMeYourNameAndPhone==NAME==";

    /**
     * 监听群聊，触发启动事件。
     */
    @OnGroup
    @Filter(value = "探索地图", matchType = MatchType.EQUALS)
    public void explore(GroupMsg m, ListenerContext context, Sender sender) {
        // 得到session上下文，并断言它的确不是null
        final ContinuousSessionScopeContext sessionContext = (ContinuousSessionScopeContext) context.getContext(ListenerContext.Scope.CONTINUOUS_SESSION);
        assert sessionContext != null;

        final String groupCode = m.getGroupInfo().getGroupCode();
        final String code = m.getAccountInfo().getAccountCode();
        String nickname = m.getAccountInfo().getAccountNickname();

        // 通过群号和账号拼接一个此人在此群中的唯一key
        String key = groupCode + ":" + code;

        /*
            注意！你应当考虑一个问题：同一个人同时触发多次同样的会话，比如它同时发了两次 'start'.
            这个问题的解决应当由你自行解决，比如创建会话之前，先去检查是否已经存在。
         */
        sender.sendGroupMsg(m, "探索中...");
        List<WarMap> list = warMapService.explore(code, groupCode);
        List<MapType> typeList = mapTypeService.getAll();
        Map<String, String> typeMap = new HashMap<>(4);
        for (MapType type : typeList) {
            typeMap.put(type.getTypeCode(), type.getName());
        }

        StringBuilder msg = new StringBuilder(nickname + "领主，探索到以下区域：\n");
        for (int i = 0; i < list.size(); i++) {
            WarMap warMap = list.get(i);
            msg.append(i + 1).append(".").append(typeMap.get(warMap.getType())).append("(").append(warMap.getX()).append(",").append(warMap.getY()).append(")\n");

        }
        msg.append("请发送【侦察+编号】进行侦察，例：侦察1 \n");
        // 发送提示信息
        sender.sendGroupMsg(m, msg.toString());
        List<WarMap> warMaps = new ArrayList<>();
        // 创建回调函数 SessionCallback 实例。
        // 通过 SessionCallback.builder 进行创建
        final SessionCallback<Integer> callback = SessionCallback.<Integer>builder().onResume(warMapIndex -> {
            /*
             * 侦察
             */
            if (warMapIndex > list.size()) {
                sender.sendGroupMsg(m, "选择的区域不存在！");
                return;
            } else {
                WarMap warMap = list.get(warMapIndex);
                StringBuilder msg1 = new StringBuilder(MsgResult.warMapInfo(nickname, warMap, warMapIndex, typeMap));

                String warMapAccountCode = warMap.getAccountCode();
                //判断是否有人占领
                if (warMapAccountCode != null && !"".equals(warMapAccountCode)) {
                    Getter getter = manager.getDefaultBot().getSender().GETTER;
                    GroupMemberInfo memberInfo = getter.getMemberInfo(groupCode, warMapAccountCode);
                    msg1.append(memberInfo.getAccountNickname()).append("(").append(warMap.getAccountCode()).append(")占领\n");
                } else {
                    msg1.append("无领主\n");
                }
                msg1.append("该区域士兵数量：").append(warMap.getSoldierNum());
                /*
                可动用的士兵获取
                 */
                warMaps.addAll(warMapService.exploreByWarId(code, groupCode, warMap));
                msg1.append("您可派遣的城池信息：\n");
                for (int i = 0; i < warMaps.size(); i++) {
                    WarMap warMap1 = warMaps.get(i);
                    msg1.append(i + 1).append(".").append(typeMap.get(warMap1.getType())).append("(").append(warMap1.getX()).append(",").append(warMap1.getY()).append(") 士兵：").append(warMap1.getSoldierNum()).append("\n");

                }
                msg1.append("是否攻占？(派遣【城池号】城池【士兵数量】士兵攻占/撤退)\n例派遣1城池10士兵攻占");
                sender.sendGroupMsg(m, msg1.toString());
            }

            // 这是在回调中继续创建一个会话。
            // 这里通过 sessionContext.waiting(group, key, OnResume) 快速创建一个回调，只处理正确结果的情况，而不处理其他（出现错误、关闭事件等）
            // wait, 这里使用的是 name_group，也就是等待提供姓名的group，但是key还是那个人对应唯一的key
            sessionContext.waiting(NAME_GROUP, key, flag -> {
                String s = flag.toString();
                if (s.startsWith("派遣")) {
                    String cityIndexStr = s.substring(s.indexOf("遣") + 1, s.indexOf("城池")).trim();
                    int cityIndex = Integer.parseInt(cityIndexStr);
                    WarMap warMap = warMaps.get(cityIndex - 1);
                    s = s.substring(s.indexOf("池") + 1, s.indexOf("士兵攻占")).trim();
                    Integer num = Integer.valueOf(s);

                    Integer soldierNum = warMap.getSoldierNum();
                    //拥有的士兵数量多于指令数量
                    if (soldierNum >= num) {
                        //执行占领操作
                        /*
                        如果占领成功士兵就会留在那边，如果占领失败，士兵就都死了
                         */
                        warMap.setSoldierNum(soldierNum - num);
                        boolean capture = cityService.capture(code, groupCode, list.get(warMapIndex), num);
                        warMapService.updateById(warMap);
                        //判断是否占领成功
                        if (capture) {
                            sender.sendGroupMsg(m, nickname + "领主，占领成功！");
                        } else {
                            sender.sendGroupMsg(m, nickname + "领主，占领失败！");
                        }

                    } else {
                        sender.sendGroupMsg(m, nickname + "领主，您当前并未有" + num + "数量的士兵！");
                    }
                } else {
                    sender.sendGroupMsg(m, "已撤退！");
                }
            });

        }).onError(e -> {
            // 这里是第一个会话，此处通过 onError 来处理出现了异常的情况，例如超时
            if (e instanceof TimeoutException) {
                // 超时事件是 waiting的第三个参数，可以省略，默认下，超时时间为 1分钟
                // 这个默认的超时时间可以通过配置 simbot.core.continuousSession.defaultTimeout 进行指定。如果小于等于0，则没有超时，但是不推荐不设置超时。
                System.out.println("onError: 超时啦: " + e);
            } else {
                System.out.println("onError: 出错啦: " + e);
            }
        }).onCancel(e -> {
            // 这里是第一个会话，此处通过 onCancel 来处理会话被手动关闭、超时关闭的情况的处理，有些时候会与 orError 同时被触发（例如超时的时候）
            System.out.println("onCancel 关闭啦: " + e);
        }).build(); // build 构建

        // 这里开始等待第一个会话。
        sessionContext.waiting(PHONE_GROUP, key, callback);
    }


    /**
     * 针对上述第一个会话的监听。
     * 因为这里是监听 获取手机号 的事件，因此此处的 Filter为 \\d 正则。
     * 通过 @OnlySession来限制，当且仅当由 PHONE_GROUP 这个组的会话的时候，此监听函数才会生效。
     */
    @OnGroup
    @OnlySession(group = PHONE_GROUP)
    public void phone(GroupMsg m, ListenerContext context) {
        // 得到session上下文。

        final ContinuousSessionScopeContext session = (ContinuousSessionScopeContext) context.getContext(ListenerContext.Scope.CONTINUOUS_SESSION);
        assert session != null;

        final String groupCode = m.getGroupInfo().getGroupCode();
        final String code = m.getAccountInfo().getAccountCode();

        // 拼接出来这个人对应的唯一key
        String key = groupCode + ":" + code;

        String text = m.getText();
        text = text.replace("侦察", "").trim();
        int integer = Integer.parseInt(text);

        // 尝试将这个phone推送给对应的会话。
        session.push(PHONE_GROUP, key, integer - 1);

        /*
            注意！如果你的会话结果逻辑比较复杂，那么你应该先判断这个key对应的会话是否存在，然后再进行推送。
            session.push 在没有发现对应的会话的情况下，会返回false。
         */

    }

    /**
     * 针对上述第二个会话的监听。
     * 因为这里是监听 获取姓名 的事件。
     * 通过 @OnlySession来限制，当且仅当由 NAME_GROUP 这个组的会话的时候，此监听函数才会生效。
     */
    @OnGroup
    @OnlySession(group = NAME_GROUP)
    public void onName(GroupMsg m, ListenerContext context) {
        // 得到session上下文。


        final ContinuousSessionScopeContext session = (ContinuousSessionScopeContext) context.getContext(ListenerContext.Scope.CONTINUOUS_SESSION);
        assert session != null;
        final String groupCode = m.getGroupInfo().getGroupCode();
        final String code = m.getAccountInfo().getAccountCode();
        // 拼接出来一个对应的唯一key
        String key = groupCode + ":" + code;

        // 尝试推送结果
        session.push(NAME_GROUP, key, m.getText());
    }

}

